/// 结构体（structure，缩写成 struct）有 3 种类型，使用 struct 关键字来创建：
//
// 元组结构体（tuple struct），事实上就是具名元组而已。
// 经典的 C 语言风格结构体（C struct）。
// 单元结构体（unit struct），不带字段，在泛型中很有用。

struct User {
    active: bool,
    username: String,
    email: String,
    sign_in_count: u64,
}

fn main() {
    // 结构体
    // struct_demo();

    // 结构体复制后的，非常规类型字段的所有权发生转移
    // struct_field_ownership();

    // 内存
    struct_mem();

    // 结构体打印
    struct_print();

    struct_dbg();
}

fn struct_dbg() {
    #[derive(Debug)]
    struct Rectangle {
        width: u32,
        height: u32,
    }

    let scale = 2;
    let rect1 = Rectangle {
        width: dbg!(30 * scale),
        height: 50,
    };

    dbg!(&rect1);
}

fn struct_print() {
    #[derive(Debug)]
    struct Rectangle {
        width: u32,
        height: u32,
    }

    fn main() {
        let rect1 = Rectangle {
            width: 30,
            height: 50,
        };

        println!("rect1 is {:?}", rect1);
    }
}

fn struct_field_ownership() {
    let user1 = User {
        email: String::from("someone@example.com"),
        username: String::from("someusername123"),
        active: true,
        sign_in_count: 1,
    };
    let user2 = User {
        active: user1.active,
        username: user1.username,
        email: String::from("another@example.com"),
        sign_in_count: user1.sign_in_count,
    };
    println!("{}", user1.active);
// 下面这行会报错
//     println!("{:?}", user1);
}

fn struct_mem() {
    #[derive(Debug)]
    struct File {
        name: String,
        data: Vec<u8>,
    }

    let f1 = File {
        name: String::from("f1.txt"),
        data: Vec::new(),
    };

    let f1_name = &f1.name;
    let f1_length = &f1.data.len();

    println!("{:?}", f1);
    println!("{} is {} bytes long", f1_name, f1_length);
}

fn struct_demo() {
    // 使用简单的写法初始化字段，并创建结构体
    let name = String::from("Peter");
    let age = 27;
    let peter = Person { name, age };

    // 以 Debug 方式打印结构体
    println!("{:?}", peter);

    // 实例化结构体 `Point`
    let point = Point { x: 1.0, y: 2.0 };

    // 访问 point 的字段
    println!("point coordinates: ({}, {})", point.x, point.y);

    // 使用结构体更新语法创建新的 point，
    // 这样可以用到之前的 point 的字段
    let bottom_right = Point { x: 5.2, ..point };

    // `bottom_right.y` 与 `point.y` 一样，因为这个字段就是从 `point` 中来的
    println!("second point: ({}, {})", bottom_right.x, bottom_right.y);

    // 使用 `let` 绑定来解构 point
    let Point {
        x: left_edge,
        y: top_edge,
    } = point;
    println!("point has left edge {}, top edge {}", left_edge, top_edge);

    let _rectangle = Rectangle {
        // 结构体的实例化也是一个表达式
        top_left: Point {
            x: left_edge,
            y: top_edge,
        },
        bottom_right: bottom_right,
    };

    let area: f32 = rectangle_area(_rectangle);
    println!("rectangle area is {}", area);

    // 实例化一个单元结构体
    let _unit = UnitStruct;

    // 实例化一个元组结构体
    let pair = TupleStruct(1, 0.1);

    // 访问元组结构体的字段
    println!("pair contains {:?} and {:?}", pair.0, pair.1.to_string());

    // 解构一个元组结构体
    let TupleStruct(integer, decimal) = pair;

    println!("pair contains {:?} and {:?}", integer, decimal);
}

#[derive(Debug)]
struct Person {
    name: String,
    age: u8,
}

// 单元结构体
struct UnitStruct;

// 元组结构体
struct TupleStruct(i32, f32);

// 带有两个字段的结构体
struct Point {
    x: f32,
    y: f32,
}

// 结构体可以作为另一个结构体的字段 ---- 长方形
#[allow(dead_code)]
struct Rectangle {
    // 可以在空间中给定左上角和右下角在空间中的位置来指定矩形。
    top_left: Point,
    bottom_right: Point,
}

// 计算长方形的面积
#[allow(dead_code)]
fn rectangle_area(rectangle: Rectangle) -> f32 {
    rectangle.bottom_right.x * rectangle.top_left.x
}

#[allow(dead_code)]
fn square(point: Point, size: f32) -> Rectangle {
    Rectangle {
        top_left: Point { x: size, y: size },
        bottom_right: Point {
            x: point.x + size / 2.0,
            y: point.y + size / 2.0,
        },
    }
}
